%%%-------------------------------------------------------------------
%%% File    : ptool.erl
%%% Author  :  <vjache>
%%% Description : 
%%%
%%% Created : 27 Apr 2009 by  <vjache>
%%%-------------------------------------------------------------------
-module(ptool).

-include("../include/ptool.hrl").

%% API
-export([
		 open/1,
		 pkeyfold/5,
		 obtain_acc/5,
		 create_acc/4,
		 create_acc/5,
		 send_acc/3,
		 finish_acc/2,
		 finish_all/1,
		 yield_acc/2,
		 yield_all/2,
		 yield_atwill_all/4,
		 close/1]).


%%====================================================================
%% API
%%====================================================================
open(#ptool{module=Module,open_args=ArgList}=PToolDescr) ->
	{PToolDescr,_PToolState=Module:open(ArgList)}.

%%--------------------------------------------------------------------
%% Function: 	pkeyfold(KeyFun,FoldFun,FinishFun,Acc,ListOrIter) -> [ResultAcc]
%% Description: This function traverses items in ListOrIter and 
%%				distributes them over a number of accumulating 
%%				processes accordinly key provided by KeyFun(Item).
%%				Each acc process folds items using FoldFun(Key,Item,Acc) 
%%				like in 'dict:fold', the fold stage continues until
%%				finish message recived from owner prc. Once finish msg
%%				received acc process calls FinishFun(Acc)->Result and
%%				sends result back to the owner process. Hence the result
%%				of execution of this fun is a list of results of parallel
%%				fold-finish computations.
%%--------------------------------------------------------------------

pkeyfold(PToolState,FoldFun,FinishFun,Acc,List) when is_list(List) ->
	pkeyfold(PToolState,FoldFun,FinishFun,Acc,iter:from_list(List));
pkeyfold(State,FoldFun,FinishFun,Acc,Iter) ->
	{IterFinState,ok}=iter:foreach(Iter,fun(Item)->
												Handle=obtain_acc(State,Item,FoldFun,FinishFun,Acc),
												ok=send_acc(State,Handle,Item)
								   end),
	ok=iter:close(IterFinState),
	Promises=finish_all(State),
	yield_all(State,Promises).
%new_pkeyfold_pipe()
obtain_acc({PToolDescr,PToolState},Item,FoldFun,FinishFun,Acc) ->
	Mod=PToolDescr#ptool.module,
	Mod:obtain_acc(PToolState,Item,FoldFun,FinishFun,Acc).
create_acc({PToolDescr,PToolState},FoldFun,FinishFun,Acc) ->
	create_acc({PToolDescr,PToolState},node(),FoldFun,FinishFun,Acc).
create_acc({PToolDescr,PToolState},Node,FoldFun,FinishFun,Acc) ->
	Mod=PToolDescr#ptool.module,
	Mod:create_acc(PToolState,Node,FoldFun,FinishFun,Acc).
send_acc({PToolDescr,PToolState},AccHandle,Item) ->
	Mod=PToolDescr#ptool.module,
	ok=Mod:send_acc(PToolState,AccHandle,Item).
finish_acc({PToolDescr,PToolState},AccHandle) ->
	Mod=PToolDescr#ptool.module,
	_Promise=Mod:finish_acc(PToolState,AccHandle).
finish_all({PToolDescr,PToolState}) ->
	Mod=PToolDescr#ptool.module,
	_Promise=Mod:finish_all(PToolState).
yield_acc({PToolDescr,PToolState},Promise) ->
	Mod=PToolDescr#ptool.module,
	_Result=Mod:yield_acc(PToolState,Promise).
yield_all({PToolDescr,PToolState},Promises) ->
	Mod=PToolDescr#ptool.module,
	_Result=Mod:yield_all(PToolState,Promises).
yield_atwill_all({PToolDescr,PToolState},Promises,ConsumeFun,ConsumerState) ->
	Mod=PToolDescr#ptool.module,
	_ConsFinState=Mod:yield_atwill_all(PToolState,Promises,ConsumeFun,ConsumerState).

close({PToolDescr,PToolState}) ->
	Mod=PToolDescr#ptool.module,
	ok=Mod:close(PToolState).
%%====================================================================
%% Internal functions
%%====================================================================


